#include <FL/fl_ask.H>
#include <iostream>
#include "SegmentationBase.h"



/************************************
 *
 *  Constructor
 *
 ***********************************/
SegmentationBase 
::SegmentationBase()
{

  m_ImageReader                  = ImageReaderType::New();
  m_CastImageFilter2DsTo3Df = CastImage2DsTo3DfFilterType::New();
  m_CastImageFilter2DsTo3Df->SetInput( m_ImageReader->GetOutput() );
  m_CastImageFilter2DsTo2Df = CastImage2DsTo2DfFilterType::New();
  m_CastImageFilter2DsTo2Df->SetInput( m_ImageReader->GetOutput() );
  
  m_DerivativeFilter   = DerivativeFilterType::New();
  m_DerivativeFilter->SetInput( m_CastImageFilter2DsTo2Df->GetOutput() );

  m_SigmoidFilter  = SigmoidFilterType::New();
  m_SigmoidFilter->SetInput( m_DerivativeFilter->GetOutput() );
  m_SigmoidFilter->SetOutputMaximum( 1.0 );
  m_SigmoidFilter->SetOutputMinimum( 0.0 );

  m_TrialPoints = NodeContainer::New();

  m_FastMarchingFilter = FastMarchingFilterType::New();
  m_FastMarchingFilter->SetInput( m_SigmoidFilter->GetOutput() );
  m_FastMarchingFilter->SetTrialPoints( m_TrialPoints );

  m_InputThresholdFilter = ThresholdFilterType::New();
  m_InputThresholdFilter->SetInput( m_FastMarchingFilter->GetOutput() );
  m_InputThresholdFilter->SetUpperThreshold( itk::NumericTraits<InternalPixelType>::Zero ); 
  m_InputThresholdFilter->SetLowerThreshold( itk::NumericTraits<InternalPixelType>::NonpositiveMin() ); 
  m_InputThresholdFilter->SetInsideValue( 1 );
  m_InputThresholdFilter->SetOutsideValue(  0 );

    m_ThresholdFilter = ThresholdFilterType::New();




  m_SeedImage = SeedImageType::New();

  m_SeedValue = 0; // It must be set to the minus distance of the initial level set.

  m_NumberOfSeeds = 0;

  m_InputImageIsLoaded  = false;

 
  m_CastImageFilter2DfTo3Df1 = CastImage2DfTo3DfFilterType::New();

//  m_CastImageFilter2DfTo3Df1->UpdateLargestPossibleRegion();

  m_CastImageFilter2DfTo3Df2 = CastImage2DfTo3DfFilterType::New();
  m_CastImageFilter2DfTo3Df2->SetInput( m_DerivativeFilter->GetOutput() );
 
}





/************************************
 *
 *  Destructor
 *
 ***********************************/
SegmentationBase 
::~SegmentationBase()
{


}



 
/************************************
 *
 *  Load Input Image
 *
 ***********************************/
void
SegmentationBase 
::LoadInputImage( const char * filename )
{
  if( !filename )
  {
    return;
  }

  m_ImageReader->SetFileName( filename );
  m_ImageReader->UpdateLargestPossibleRegion();
//  m_CastImageFilter2DsTo3Df->UpdateLargestPossibleRegion();

InputImageType2Ds::RegionType region2D
            = m_ImageReader->GetOutput()->GetBufferedRegion();

  InputImageType2Ds::SizeType size2D = region2D.GetSize();
 // cout<<"region2D:\n"<<region2D.GetSize();
  // Allocate a image of seeds of the same size
//  InternalImageType3Df::RegionType region 
  //          = m_CastImageFilter2DsTo3Df->GetOutput()->GetBufferedRegion();

 // InternalImageType3Df::SizeType size = region.GetSize();
  /*
  cout<<"region3D:\n"<<region.GetSize();
  
  }*/
//  cout<<"size["<<0<<"]="<<size[0];
  for(unsigned int i=0; i<ImageDimension2D; i++)
    {
    if( size2D[i] < 10 )
      {
//		  cout<<"size["<<i<<"]="<<size2D[i];
      this->ShowStatus("Image must be 2D and with at least 10 pixels along each Dimension.");
      itk::ExceptionObject excp;
      excp.SetDescription("Image must be 2D and with at least 10 pixels along each Dimension.");
      throw excp;
      }
    }


//  InternalImageType2Df::SizeType size2D = {size[0],size[1]};
  m_SeedImage->SetRegions( region2D );
  m_SeedImage->Allocate();
  m_SeedImage->FillBuffer( itk::NumericTraits<SeedImageType::PixelType>::Zero );

  m_FastMarchingFilter->SetOutputSize( size2D );

  m_InputImageIsLoaded = true;

}




/********************************************
 *
 *  Set the seed. From this seed an Initial
 *  level set image is generated 
 *
 *******************************************/
void
SegmentationBase 
::AddSeed( const IndexType & seedPosition  )
{

  // setup trial points
  NodeType node;
  
  node.SetValue( m_SeedValue );
  node.SetIndex( seedPosition );

  m_TrialPoints->InsertElement( m_NumberOfSeeds, node );
//cout<<seedPosition;
  IndexType position= seedPosition;
  for(int m=-5;m<6;m++)
  {
	position[0] = seedPosition[0]+m;
	m_SeedImage->SetPixel( position, itk::NumericTraits< SeedPixelType >::max()  );
  }
	position = seedPosition;
  for(int m=-5;m<6;m++)
  {
	position[1] = seedPosition[1]+m;
	m_SeedImage->SetPixel( position, itk::NumericTraits< SeedPixelType >::max()  );
  }

  m_NumberOfSeeds++;
  
}



  
/************************************
 *
 *  Clear Seeds
 *
 ***********************************/
void
SegmentationBase 
::ClearSeeds()
{
  m_TrialPoints->Initialize(); 
  m_NumberOfSeeds = 0;
  m_FastMarchingFilter->Modified();
  m_SeedImage->FillBuffer( itk::NumericTraits<SeedImageType::PixelType>::Zero );
}


 

/********************************************
 *
 *  Set the Sigma value
 *
 *******************************************/
void
SegmentationBase 
::SetSigma( double value )
{
  m_DerivativeFilter->SetSigma( value );
}



/********************************************
 *
 *  Set the Threshold value for edge strenght
 *
 *******************************************/




/************************************
 *
 *  Compute Gradient Magnitude
 *
 ***********************************/
void
SegmentationBase
::ComputeGradientMagnitude( void )
{
  this->ShowStatus("Computing Gradient Image");
  m_DerivativeFilter->UpdateLargestPossibleRegion();
}


 
/************************************
 *
 *  Compute Fast Marching
 *
 ***********************************/
void
SegmentationBase
::ComputeFastMarching( void )
{
  this->ShowStatus("Computing Fast Marching");
  m_FastMarchingFilter->UpdateLargestPossibleRegion();
}


  
/************************************
 *
 *  Compute Zero Set
 *
 ***********************************/
void
SegmentationBase
::ComputeZeroSet( void )
{
  this->ShowStatus("Computing Zero Set");
  // This will also update the FastMarching
  m_InputThresholdFilter->UpdateLargestPossibleRegion();
}


 



/************************************
 *
 *  Compute Edge Potential Image
 *
 ***********************************/
void
SegmentationBase
::ComputeEdgePotential( void )
{
  this->ComputeGradientMagnitude();
  this->ShowStatus("Computing Edge Potential Image");
  m_SigmoidFilter->UpdateLargestPossibleRegion();
}


  

/************************************
 *
 *  Start Segmentation
 *
 ***********************************/






/************************************
 *
 *  Stop Segmentation
 *
 ***********************************/
void
SegmentationBase
::SetZeroSetValue( InternalPixelType value )
{
  // By starting the FastMarching front at this value,
  // the zero set will end up being placed at distance
  // = value from the seeds. That can be seen as computing
  // a distance map from the seeds.
  m_SeedValue = - value;

  NodeContainer::Iterator nodeItr = m_TrialPoints->Begin();
  NodeContainer::Iterator endNode = m_TrialPoints->End();
  while( nodeItr != endNode )
    {
    nodeItr.Value().SetValue( m_SeedValue );
    ++nodeItr;
    }
  m_FastMarchingFilter->Modified();
}



/************************************
 *
 *  Stop Segmentation
 *
 ***********************************/
void
SegmentationBase
::Stop( void )
{
  // TODO: add a Stop() method to Filters

}





void SegmentationBase
::LoadInputImage()
{}

void SegmentationBase
::ShowStatus(const char * text)
{}
